package cn.wx.utils;

import cn.wx.session.Mapper;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class Executor {

    public <E> List<E> selectList(Mapper mapper, Connection conn) {
        String sql = mapper.getSql();
        String resultType = mapper.getResultType();
        PreparedStatement ps = null;
        ResultSet set = null;
        try {
            Class<E> result = (Class<E>) Class.forName(resultType);
            ps = conn.prepareStatement(sql);
            set = ps.executeQuery();
            List<E> list = new ArrayList<>();
            while (set.next()) {
                E e = result.getConstructor().newInstance();
                int columns = set.getMetaData().getColumnCount();
                for (int i = 1; i <= columns; i++) {
                    String columnName = set.getMetaData().getColumnName(i).toLowerCase(Locale.ROOT); // 列名
                    Object columnValue = set.getObject(i); // 列的值
                    if (columnName.contains("_")) { // 如果列名含有下划线，进行处理
                        String[] names = columnName.split("_");
                        StringBuilder name = new StringBuilder(names[0]);
                        for (int j = 1; j < names.length; j++) {
                            name.append(names[j].substring(0,1).toUpperCase(Locale.ROOT))
                                    .append(names[j].substring(1));
                        }
                        columnName = name.toString();
                    }
                    if (columnName.startsWith("is_")) {
                        columnName = columnName.replace("is_", "");
                    }

                    // 通过反射将列中的值封装到对象里
                    PropertyDescriptor prop = new PropertyDescriptor(columnName, result);
                    Method method = prop.getWriteMethod();
                    // 如果值是日期，需要进行转换
                    if (Date.class.equals(prop.getReadMethod().getReturnType())) {
                        if (columnValue instanceof LocalDateTime temp) {
                            Date value = Date.from(temp.atZone(ZoneId.systemDefault()).toInstant());
                            method.invoke(e, value);
                            continue;
                        }
                    }
                    method.invoke(e, columnValue);
                }
                list.add(e); // 将一行数据封装的对象放进 list 集合
            }
            return list;
        } catch (ClassNotFoundException | SQLException | IllegalAccessException | InstantiationException |
                 NoSuchMethodException | InvocationTargetException | IntrospectionException e) {
            throw new RuntimeException(e);
        } finally {
            close(ps, set);
        }
    }

    public void close(PreparedStatement ps, ResultSet set) {
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (set != null) {
            try {
                set.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
